iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
Software Development

我的SpringBoot絕學:7+2個專案,從新手變專家系列 第 18

Day18 第六個Spring Boot專案:小型電商購物車系統(4)註冊與登入

  • 分享至 

  • xImage
  •  

註冊

接下來,我們開始處理註冊功能,建立Entity。

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String email;
    private String password;

    public User() {

    }

    public User(Long id, String email, String password) {
        this.id = id;
        this.email = email;
        this.password = password;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

Repository

public interface UserRepository extends JpaRepository<User, Long> {
    User findByEmail(String email);
}

Service

新增用戶時,檢查email是否註冊過,如果有註冊就顯示例外,提醒使用者已經註冊了。

@Service
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    public void createUser(User user) throws Exception {
        User isEmailExists = userRepository.findByEmail(user.getEmail());

        if(isEmailExists != null) {
            throw new Exception("Error: Email is already registered.");
        }

        User createdUser = new User();
        createdUser.setEmail(user.getEmail());
        createdUser.setPassword(passwordEncoder.encode(user.getPassword()));

        userRepository.save(createdUser);
    }
}

上面這三段程式碼,相信大家應該都很熟悉了,不多做解釋。

修改AuthController.java,處理註冊請求,從request中取得email和密碼。

@PostMapping("/signup")
    public ResponseEntity<AuthResponse> createUserHandler(@RequestBody User user) throws Exception {
        userService.createUser(user);

        String token = jwtProvider.generateToken();

        AuthResponse authResponse = new AuthResponse();
        authResponse.setJwt(token);
        authResponse.setMessage("Signup Success");

        return new ResponseEntity<>(authResponse, HttpStatus.CREATED);
    }

啟動專案,測試註冊功能,記得設定email和密碼。

我們會取得token和Signup Success的訊息,也可以檢查資料庫中是不是有我們剛註冊的email。

{
	"email": "user@new.com",
	"password": "12345678"
}

JWT增加夾帶email

我們再註冊一個帳號,取得另一個token。

現在我們有兩個token了,貼到jwt.io驗證,發覺我們無法辨別token來自於哪個用戶。

因此我們要在產生token時夾帶email地址。

修改AuthController.java,在註冊時,要傳送email給JWTProvider

        String token = jwtProvider.generateToken(user.getEmail());

修改JWTProvider.java

增加夾帶emai的程式碼,並且標明這個欄位是email,這樣方便我們解讀。

public String generateToken(String email) {
        return Jwts.builder()
                .setIssuedAt(new Date())
                .setExpiration(new Date(new Date().getTime() + 12 * 60 * 60 * 1000))
                .claim("email", email)
                .signWith(key)
                .compact();
    }

來到https://jwt.io/#debugger-io

把得到的token貼上,就能從payload欄位找到email,用JWT_CONSTANT取代your-256-bit-secret,就會顯示Signature verified。

就算有心人想要修改成別人的email,在沒有正確的JWT_CONSTANT的情況下,無法通過驗證。

登入

註冊功能完成後,我們就能開始進行編寫登入的功能,登入成功就會回傳token和成功登入的訊息。

根據提供的email在資料庫中找尋用戶,如果找不到或密碼不對,就顯示錯誤。

這邊刻意不明說是email錯誤還是密碼錯誤,避免駭客使用登入,來找尋有人使用的email。

雖然註冊的部分,有個錯誤訊息是email已經註冊了,由於我們正在開發中,所以保留這個訊息。

等到專案完成了,可以修改這個錯誤訊息,改成顯示email不符合規定,就沒人知道是email重複了。

//AuthController.java

@PostMapping("/login")
    public ResponseEntity<AuthResponse> loginHandler(@RequestBody User user) throws Exception {
        User foundUser  = userService.findUserByEmail(user.getEmail());

        if(foundUser == null || !passwordEncoder.matches(user.getPassword(), foundUser.getPassword())) {
            throw new Exception("Invalid email or password");
        }

        String token = jwtProvider.generateToken(foundUser.getEmail());
        AuthResponse authResponse = new AuthResponse();
        authResponse.setJwt(token);
        authResponse.setMessage("Login Success");
        return new ResponseEntity<>(authResponse, HttpStatus.OK);
    }

在UserService.java,添加根據email尋找用戶的程式碼。

public User findUserByEmail(String email){
        return userRepository.findByEmail(email);
    }

測試登入功能,使用先前註冊的email和密碼進行登入,就能得到token和成功的訊息。


上一篇
Day17 第六個Spring Boot專案:小型電商購物車系統(3)JWT
下一篇
Day19 第六個Spring Boot專案:小型電商購物車系統(5)導入token驗證
系列文
我的SpringBoot絕學:7+2個專案,從新手變專家31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言